package com.cheetah.start.common.shoesImg;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import java.util.ArrayList;
import java.util.List;

public class SimilarityCalculator {

    /**
     * 计算综合相似度
     */
    public static SimilarityResult calculateSimilarity(ContourFeature feature1, ContourFeature feature2) {
        SimilarityResult result = new SimilarityResult();

        // 计算各种特征的相似度
        result.colorSimilarity = calculateColorSimilarity(feature1.colorHistogram, feature2.colorHistogram);
        result.textureSimilarity = calculateTextureSimilarity(feature1.textureFeature, feature2.textureFeature);
        result.shapeSimilarity = calculateShapeSimilarity(feature1.shapeFeature, feature2.shapeFeature);
        result.edgeSimilarity = calculateEdgeSimilarity(feature1.edgeFeature, feature2.edgeFeature);

        // 计算综合相似度（加权平均）
        result.overallSimilarity = calculateWeightedSimilarity(result);

        return result;
    }

    /**
     * 计算颜色相似度
     */
    private static double calculateColorSimilarity(Mat hist1, Mat hist2) {
        // 使用相关性方法比较直方图
        return Imgproc.compareHist(hist1, hist2, Imgproc.CV_COMP_CORREL);
    }

    /**
     * 计算纹理相似度
     */
    private static double calculateTextureSimilarity(Mat texture1, Mat texture2) {
        // 使用卡方距离比较纹理特征
        double chiSq = Imgproc.compareHist(texture1, texture2, Imgproc.CV_COMP_CHISQR);
        // 转换为相似度（距离越小，相似度越高）
        return Math.max(0, 1 - chiSq / 2.0);
    }

    /**
     * 计算形状相似度
     */
    private static double calculateShapeSimilarity(Mat shape1, Mat shape2) {
        // 使用余弦相似度比较形状特征
        return computeCosineSimilarity(shape1, shape2);
    }

    /**
     * 计算边缘相似度
     */
    private static double calculateEdgeSimilarity(Mat edge1, Mat edge2) {
        // 使用巴氏距离比较边缘特征
        double bhattacharyya = Imgproc.compareHist(edge1, edge2, Imgproc.CV_COMP_BHATTACHARYYA);
        // 转换为相似度（距离越小，相似度越高）
        return Math.max(0, 1 - bhattacharyya);
    }

    /**
     * 计算加权综合相似度
     */
    private static double calculateWeightedSimilarity(SimilarityResult result) {
        // 权重配置（可根据实际需求调整）
        double colorWeight = 0.4;    // 颜色权重
        double textureWeight = 0.3;  // 纹理权重
        double shapeWeight = 0.2;    // 形状权重
        double edgeWeight = 0.1;     // 边缘权重

        double weightedSum = result.colorSimilarity * colorWeight +
                result.textureSimilarity * textureWeight +
                result.shapeSimilarity * shapeWeight +
                result.edgeSimilarity * edgeWeight;

        return Math.max(0, Math.min(1, weightedSum));
    }

    /**
     * 计算余弦相似度
     */
    private static double computeCosineSimilarity(Mat v1, Mat v2) {
        double dotProduct = v1.dot(v2);
        double norm1 = Core.norm(v1, Core.NORM_L2);
        double norm2 = Core.norm(v2, Core.NORM_L2);

        if (norm1 == 0 || norm2 == 0) return 0;
        return dotProduct / (norm1 * norm2);
    }

    /**
     * 批量计算所有轮廓之间的相似度
     */
    public static List<SimilarityMatrix> calculateAllSimilarities(List<ContourFeature> features) {
        List<SimilarityMatrix> matrices = new ArrayList<>();

        for (int i = 0; i < features.size(); i++) {
            for (int j = i + 1; j < features.size(); j++) {
                SimilarityResult result = calculateSimilarity(features.get(i), features.get(j));

                SimilarityMatrix matrix = new SimilarityMatrix();
                matrix.index1 = i;
                matrix.index2 = j;
                matrix.similarity = result;

                matrices.add(matrix);
            }
        }

        // 按相似度排序
        matrices.sort((a, b) -> Double.compare(b.similarity.overallSimilarity, a.similarity.overallSimilarity));

        return matrices;
    }
}

/**
 * 相似度结果类
 */
class SimilarityResult {
    double colorSimilarity;
    double textureSimilarity;
    double shapeSimilarity;
    double edgeSimilarity;
    double overallSimilarity;
}

/**
 * 相似度矩阵类
 */
class SimilarityMatrix {
    int index1;
    int index2;
    SimilarityResult similarity;
}
